package com.cloud.v2.auth.config;

import com.cloud.v2.auth.service.AuthUserDetailsServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.security.SecurityProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.factory.PasswordEncoderFactories;
import org.springframework.security.crypto.password.PasswordEncoder;

import javax.annotation.Resource;

/**
 * Security大管家
 * @Author fuce
 * @Date 2020/11/16 23:51
 * @Version 1.0
 **/
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true, jsr250Enabled = true)
public class OAuthWebSecurityConfigurer extends WebSecurityConfigurerAdapter {

    @Resource
    private AuthUserDetailsServiceImpl authUserDetailsServiceImpl;


    /**
     * https://d.wps.cn/v/8qWT4
     * anyRequest          |   匹配所有请求路径
     * access              |   SpringEl表达式结果为true时可以访问
     * anonymous           |   匿名可以访问
     * denyAll             |   用户不能访问
     * fullyAuthenticated  |   用户完全认证可以访问（非remember-me下自动登录）
     * hasAnyAuthority     |   如果有参数，参数表示权限，则其中任何一个权限可以访问
     * hasAnyRole          |   如果有参数，参数表示角色，则其中任何一个角色可以访问
     * hasAuthority        |   如果有参数，参数表示权限，则其权限可以访问
     * hasIpAddress        |   如果有参数，参数表示IP地址，如果用户IP和参数匹配，则可以访问
     * hasRole             |   如果有参数，参数表示角色，则其角色可以访问
     * permitAll           |   用户可以任意访问
     * rememberMe          |   允许通过remember-me登录的用户访问
     * authenticated       |   用户登录后可访问
     */
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable();
             http
                 //根据认证的安全实体信息跟踪session，保证所有关联一个安全实体的session都能被跟踪到
                .sessionManagement()
                // STATELESS 解释： Spring Security永远不会创建HttpSession，它不会使用HttpSession来获取SecurityContext
                //ALWAYS 解释： 总是创建HttpSession
                //IF_REQUIRED 解释：Spring Security只会在需要时创建一个HttpSession
                //NEVER 解释：Spring Security不会创建HttpSession，但如果它已经存在，将可以使用HttpSession
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and().authorizeRequests()
                //对于获取token的rest api要允许匿名访问
                .antMatchers("/v2-auth/**").permitAll()
                //除上面外的所有请求全部需要鉴权认证
                .anyRequest().authenticated()
                .and()
                //开启httpbasic认证
                .httpBasic();
            // 禁用缓存
            http.headers().cacheControl();
    }


    /**
     * password 支持多种编码
     */
    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }



    /**
     * 这一步的配置是必不可少的，否则SpringBoot会自动配置一个AuthenticationManager,覆盖掉内存中的用户
     */
    @Override
    @Bean
    public AuthenticationManager authenticationManagerBean() throws Exception{
        return super.authenticationManagerBean();
    }

    @Override
    @Bean
    public UserDetailsService userDetailsServiceBean() throws Exception {
        return new AuthUserDetailsServiceImpl();
    }

    /**
     * 这个方法是去数据库查询用户的密码，做权限验证
     * @Author: fuce
     * @Date: 2020/11/22
     **/
    @Autowired
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {

        auth.userDetailsService(authUserDetailsServiceImpl).passwordEncoder(new CustomPasswordEncoder());

    }

    /**
     * 忽略资源
     * @param web
     * @throws Exception
     */
//    @Override
//    public void configure(WebSecurity web) throws Exception {
//        // 将 check_token 暴露出去，否则资源服务器访问时报 403 错误
//        web.ignoring().antMatchers("/oauth/check_token");
//    }







}
